﻿using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace EasyTCP
{
    public class EasyServer
    {

        #region private

        /// <summary> 唯一套接字 </summary>
        static Socket p_server = null;
        /// <summary> 不允许用户自己创建 </summary>
        private EasyServer( ) { }


        #endregion


        #region public
        /// <summary> 编码格式 </summary>
        public static Encoding bufferEncoder = Encoding.Default;

        public delegate bool onMsgProc( Socket arg0, string arg1 );
        /// <summary> 当有接收到新的数据时调用 </summary>
        public static onMsgProc onDataReceivedCallback;
        /// <summary> 当新增客户端连接时调用 </summary>
        public static Action<Socket> onClientLinkCallback;
        /// <summary> 当客户端断开连接时调用 </summary>
        public static Action<Socket> onClientLogoutCallback;
        /// <summary> 当客户端意外掉线时调用 </summary>
        public static Action<Socket> onClientLostConnectionCallback;

        /// <summary> 共享Socket 不允许修改 </summary>
        public static Socket shareSocketInstance { get { return p_server; } }

        /// <summary> 启动服务器 </summary>
        public static void Start( string port, int maxListenCount )
        {
            p_server = new Socket( AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp );
            var endPoint = new IPEndPoint( IPAddress.Any, Convert.ToInt32( port ) );

            try
            {

                p_server.Bind( endPoint );
                p_server.Listen( maxListenCount );

                var T1 = new Thread( ( ) =>
                {

                    while ( true )
                    {
                        var newAccept = p_server.Accept( );//阻塞接收新的客户端接入
                        Console.WriteLine( $"ip: {newAccept.RemoteEndPoint.ToString( )} Linked......" );
                        onClientLinkCallback?.Invoke( newAccept );//新客户端连接

                        var T2 = new Thread( ( ) =>
                        {

                            byte[] buffer = new byte[1024 * 1024];
                            bool runState = true;

                            try
                            {


                                while ( runState )
                                {
                                    int len = newAccept.Receive( buffer, 0, buffer.Length, SocketFlags.None );
                                    //客户端正常退出
                                    if ( len == 0 )
                                    {
                                        Console.WriteLine( $"ip: {newAccept.RemoteEndPoint.ToString( )} Logout......" );
                                        onClientLogoutCallback?.Invoke( newAccept );
                                        return;
                                    }

                                    runState = onDataReceivedCallback( newAccept, bufferEncoder.GetString( buffer, 0, len ) );
                                }
                            }
                            catch
                            {
                                //掉线
                                Console.WriteLine( $"ip: {newAccept.RemoteEndPoint.ToString( )} lost connection......" );
                                onClientLostConnectionCallback?.Invoke( newAccept );
                            }

                        } );
                        T2.IsBackground = true;
                        T2.Start( );
                    }

                } );
                T1.IsBackground = true;
                T1.Start( );

            }
            catch ( SocketException e )
            {

                Console.WriteLine( e.StackTrace );
            }
            catch ( Exception e )
            {

                Console.WriteLine( e.StackTrace );
            }
        }

        /// <summary> 向指定客户端发送消息 </summary>
        public static void Send(Socket caller,string data )
        {
            caller.Send( bufferEncoder.GetBytes( data ) );
        }
        #endregion

    }

}
